#include "object.h"

#include "face.h"

Object::Object(int _id) : id(_id){
    selected = false;
    convexHull = false;
//    showStepByStepFristTime = false;
}

Object::~Object(){
    Face *f;
    unsigned int size = faces.size();
    for(unsigned int i = 0; i < size; i++){
        f = faces.back();
        faces.pop_back();
        delete f;
    }
    Edge *e;
    size = edges.size();
    for(unsigned int i = 0; i < size; i++){
        e = edges.back();
        edges.pop_back();
        delete e;
    }
    Vertex *v;
    size = vertices.size();
    for(unsigned int i = 0; i < size; i++){
        v = vertices.back();
        vertices.pop_back();
        delete v;
    }
}

int Object::getID() const{
    return id;
}

void Object::select(bool _s){
    selected = _s;
}

bool Object::isSelected(){
    return selected;
}

void Object::setConvexHull(bool _ch){
    convexHull = _ch;
    if(!convexHull){
        Face *f;
        unsigned int size = faces.size();
        for(unsigned int i = 0; i < size; i++){
            f = faces.back();
            faces.pop_back();
            delete f;
        }
        Edge *e;
        size = edges.size();
        for(unsigned int i = 0; i < size; i++){
            e = edges.back();
            edges.pop_back();
            delete e;
        }
        Vertex *v;
        size = vertices.size();
        for(unsigned int i = 0; i < size; i++){
            v = vertices.at(i);
            v->setEdge(NULL, true);
            v->setIsBoundary(false);
        }
    }
}

bool Object::haveConvexHull(){
    return convexHull;
}

void Object::setTetrahedrons(bool _t){
    if(!_t){
        Tetrahedron *t;
        unsigned int size = tetrahedrons.size();
        for(unsigned int i = 0; i < size; i++){
            t = tetrahedrons.back();
            tetrahedrons.pop_back();
            delete t;
        }
        Face *f;
        size = faces.size();
        for(unsigned int i = 0; i < size; i++){
            f = faces.back();
            faces.pop_back();
            delete f;
        }
        Edge *e;
        size = edges.size();
        for(unsigned int i = 0; i < size; i++){
            e = edges.back();
            edges.pop_back();
            delete e;
        }
        Vertex *v;
        size = vertices.size();
        for(unsigned int i = 0; i < size; i++){
            v = vertices.at(i);
            v->setEdge(NULL, true);
            v->setIsBoundary(false);
        }
    }
}

bool Object::haveTetrahedrons(){
    return !tetrahedrons.empty();
}

//void Object::setStepByStepFirstTime(bool _ft){
//    showStepByStepFristTime = _ft;
//}
//
//bool Object::isStepByStepFirstTime(){
//    return showStepByStepFristTime;
//}

void Object::addTetrahedron(Tetrahedron *_f){
    tetrahedrons.push_back(_f);
}

Tetrahedron *Object::getTetrahedron(int _i){
    return tetrahedrons.at(_i);
}

int Object::sizeTetrahedrons(){
    return tetrahedrons.size();
}

void Object::addFace(Face *_f){
    faces.push_back(_f);
}
//
//bool Object::addFace(Face **_f){
//    //garantidamente só será usada quando as faces forem triangularizadas
//    Face *f;
//    std::vector<Vertex *> verticesInF;
//    std::vector<Vertex *> verticesIn_F;
//
//    bool okVertex;
//
//    for(unsigned int i = 0; i < faces.size(); i++){
//        f = faces.at(i);
//        verticesInF = f->getVerticesInThePlan();
//        verticesIn_F = (*_f)->getVerticesInThePlan();
//
//        for(unsigned int j = 0; j < verticesInF.size(); j++){
//            okVertex = false;
//            for(unsigned int k = 0; k < verticesIn_F.size(); k++){
//                if(verticesInF.at(j) == verticesInF.at(k)){
//                    okVertex = true;
//                    verticesIn_F.erase(verticesIn_F.begin() + k);
//                    break;
//                }
//            }
//            if(!okVertex) break;
//        }
//        if(okVertex){
//            delete *_f;
//            *_f = f;
//            return;
//        }
//
//    }
//
//    faces.push_back(*_f);
//    return;
//}
bool Object::addFace(Face **_f){
    //garantidamente só será usada quando as faces forem triangularizadas
    Face *f;
//    std::vector<Vertex *> verticesInF;
//    std::vector<Vertex *> verticesIn_F;

    Vertex *va, *vb, *vc, *vd, *ve, *vf;

    for(unsigned int i = 0; i < faces.size(); i++){
        f = faces.at(i);
        va = f->getVertexInThePlan(0);
        vb = f->getVertexInThePlan(1);
        vc = f->getVertexInThePlan(2);

        vd = (*_f)->getVertexInThePlan(0);
        ve = (*_f)->getVertexInThePlan(1);
        vf = (*_f)->getVertexInThePlan(2);

        if(va == vd){
            if(vb == ve){
                if(vc == vf){
                    *_f = f;
                    return true;
                }
            }else if(vb == vf){
                if(vc == ve){
                    *_f = f;
                    return false;
                }
            }
        }

        if(va == ve){
            if(vb == vf){
                if(vc == vd){
                    *_f = f;
                    return true;
                }
            }else if(vb == vd){
                if(vc == vf){
                    *_f = f;
                    return false;
                }
            }
        }

        if(va == vf){
            if(vb == vd){
                if(vc == ve){
                    *_f = f;
                    return true;
                }
            }else if(vb == ve){
                if(vc == vd){
                    *_f = f;
                    return false;
                }
            }
        }

    }

    faces.push_back(*_f);
    return true;
}

Face *Object::getFace(int _i){
    return faces.at(_i);
}

std::vector<Face *> Object::getFaces(){
    return faces;
}

int Object::sizeFaces(){
    return faces.size();
}

void Object::removeFace(Face *_f){
    int size = faces.size();
    for (int i = size; i > 0; i--){
        if ( faces.at(i - 1) == _f ){
            faces.erase(faces.begin() + i - 1);
        }
    }
    delete _f;
}

void Object::setFaces(std::vector<Face *> _f){
    faces = _f;
}

bool Object::addEdge(Edge **_e){
    Edge *e;
    for(unsigned int i = 0; i < edges.size(); i++){
        e = edges.at(i);
        if(e->getStart() == (*_e)->getStart()){
            if(e->getEnd() == (*_e)->getEnd()){
                delete *_e;
                *_e = e;
                return true;
            }
        }else if(e->getStart() == (*_e)->getEnd()){
            if(e->getEnd() == (*_e)->getStart()){
                delete *_e;
                *_e = e;
                return false;
            }
        }
    }
    edges.push_back(*_e);
    return true;
}

Edge *Object::getEdge(int _i){
    return edges.at(_i);
}

void Object::removeEdge(Edge *_e){
    int size = edges.size();
    for (int i = size; i > 0; i--){
        if ( edges.at(i - 1) == _e ){
            edges.erase(edges.begin() + i - 1);
        }
    }
    delete _e;
}

int Object::sizeEdges(){
    return edges.size();
}

void Object::addVertex(Vertex *_v){
    vertices.push_back(_v);
}

Vertex *Object::getVertex(int _i){
    return vertices.at(_i);
}

Vertex *Object::getVertexById(int _id){
    for(unsigned int i = 0; i < vertices.size(); i++){
        if(vertices.at(i)->getID() == _id)
            return vertices.at(i);
    }
    std::cout << "Não foi possivel achar o vertex de ID: " << _id << std::endl;
    return NULL;
}

int Object::sizeVertices(){
    return vertices.size();
}

std::vector<Vertex *> Object::getVertices(){
    return vertices;
}

std::vector<Vertex *> Object::selectConvexHullVertices(){
    std::vector<Vertex *> result;
    Vertex *v;
    for(unsigned int i = 0; i < vertices.size(); i++){
        v = vertices.at(i);
        if(v->getEdge()) result.push_back(v);
    }
    return result;
}

void Object::print(){
    Edge *e;
    Face *f;
    Vertex *v;
    std::vector<Vertex *> verticesInPlan;
    std::cout << "Existem " << sizeFaces() << " faces, " << sizeEdges() << " arestas e "<< sizeVertices() << " vertices."<<std::endl;
    for(int j = 0 ; j < sizeEdges() ; j++){
        e = getEdge(j);
        e->print();
    }
    std::cout << "---"<<std::endl;
    for(int j = 0 ; j < sizeFaces() ; j++){
        f = getFace(j);
        f->print();

        verticesInPlan = f->getVerticesInThePlan();
        std::cout << "Vertices do plano :";
        for(unsigned int i = 0 ; i < verticesInPlan.size(); i++){
            std::cout << " V" << verticesInPlan.at(i)->getID() << ";";
        }
        std::cout <<std::endl;
    }
    std::cout << "---"<<std::endl;
    for(int j = 0 ; j < sizeVertices() ; j++){
        v = getVertex(j);
        v->print();
    }
}
